#pragma once
#include "LinearMath\btConvexHullComputer.h"
#include "btBulletDynamicsCommon.h"
#include <iostream>
#include "LinearMath\btGeometryUtil.h"
//#include "Triangle.h"
#include "LinearMath\btConvexHull.h"

#include "btBulletCollisionCommon.h"

/// Wyznacza bryle na podstawie chmury punktow
class ConvexHull : public btConvexHullComputer
{
public:
	/// Identyfikator bryly.
	int ID;
	
	/// Konstruktor.
	ConvexHull(void);

	/// Destruktor.
	virtual ~ConvexHull(void);

	/** Sprawdza, czy punkt znajduje sie wewnatrz bryly.
	* @param p Wspolrzedne punktu.
	* @param allowOnPlane Okresla, czy punkt lezacy na scianie jest uznawany jako lezacy wewnatrz bryly.
	* @return true - lezy wewnatrz bryly, false - lezy poza bryla.
	*/
	bool IsInside(const btVector3& p, bool allowOnPlane = false);

	/// Operator porownania/
	bool operator==(const ConvexHull& other);

	/** Przeprowadza test promienia.
	* @param origin Wspolrzedne poczatku promienia.
	* @param destination Wspolrzedne konca promienia.
	* @param excludeEnds Okresla, czy moze nastapic kolizja na poczatku lub koncu promienia.
	* @return true - promien przecina przeszkode, false - brak kolizji.
	*/
	bool RayTest(const btVector3& origin, const btVector3& destination, bool excludeEnds = false);	

	/** Przeprowadza test promienia.
	* @param origin Wspolrzedne poczatku promienia.
	* @param destination Wspolrzedne konca promienia.
	* @param hitPoints Lista wszystkich punktow, w ktorych miala miejsce kolizja.
	* @param excludeEnds Okresla, czy moze nastapic kolizja na poczatku lub koncu promienia.
	* @return true - promien przecina przeszkode, false - brak kolizji.
	*/
	bool RayTest(const btVector3& origin, const btVector3& destination, btAlignedObjectArray<btVector3>& hitPoints, bool excludeEnds = false);

	/// Wyznacza plaszczyzny opisujace sciany.
	void ComputePlanes();

	/** Przeprowadza test kolizji z inna bryla.
	* @param hull Bryla, z ktora moze kolidowac obiekt.
	* @return true - jest kolizja, false - brak kolizji.
	*/
	bool Intersect(ConvexHull& hull);

	/// Lista plaszczyzn
	btAlignedObjectArray<btPlane> planes;	

	/** Sprawdza, czy dany punkt lezy na krawedzi bryly.
	* @param p Wspolrzedne punktu
	* @return true - punkt lezy na krawedzi
	*/
	bool OnEdge(const btVector3& p);

	/** Pobiera wszystkie wierzcholki tworzace dana sciane.
	* @param i Numer sciany.
	* @param outList Lista wierzcholkow tworzacych sciane.
	*/
	void GetVerticesFromFace(int i, btAlignedObjectArray<btVector3>& outList);

	/** Pobiera wszystkie punkty wchodzace w sklad danej krawedzi
	* @param i Numer krawedzi.
	* @param outList Lista punktow tworzacych krawedz.
	*/
	void GetEdgesFromFace(int i, btAlignedObjectArray<btVector3>& outList);

	/// Poprawia blad zaokraglen wywolany obliczeniami.
	inline void CorrectPrecision()
	{
		for(int i = 0; i < vertices.size(); ++i)
		{
			/*std::cout << "\n";
			Triangle::Print(vertices[i]);
			std::cout << "\t==>\t";*/

			vertices[i].setX(Round(vertices[i].getX()));
			vertices[i].setY(Round(vertices[i].getY()));
			vertices[i].setZ(Round(vertices[i].getZ()));
			/*Triangle::Print(vertices[i]);
			std::cout << std::endl;*/
		}
	}
private:
	/** Oblicza minimalna odleglosc dwoch promieni.
	* @param p1 Wspolrzedne poczatku promienia.
	* @param q1 Wspolrzedne konca promienia.
	* @param p2 Wspolrzedne poczatku promienia.
	* @param q2 Wspolrzedne konca promienia.
	* @param s Zmienna niezalezna rownania pierwszego promienia.
	* @param t Zmienna niezalezna rownania drugiego promienia.
	* @param c1 Wspolrzedne najblizszego punktu lezacego na pierszym promieniu.
	* @param c2 Wspolrzedne najblizszego punktu lezacego na drugim promieniu.
	* @return Odleglosc miedzy najblizszymi punktami dwoch promieni.
	*/
	float ClosestPointSegmentSegment(const btVector3& p1, const btVector3& q1, const btVector3& p2, const btVector3& q2, float& s, float& t, btVector3& c1, btVector3& c2);
	
	/// Wskaznik na bryle opisujaca dana chmure punktow.
	btConvexHullShape* convexHull;

	/** Sprawdza, czy podana wartosc miesci sie w zadanym zakresie i ew. ja obcina.
	* @param value Wartosc do sprawdzenia.
	* @param min Dolna granica przedzialu.
	* @param max Gorna granica przedzialu.
	* @return Zwraca nowa wartosc: jesli min <= value <= max to value, value < min to min, value > max to max.
	*/
	float clamp(float value, float min, float max);

	/** Wyznacza odleglosc punktu od plaszczyzny.
	* @param p Wspolrzedne punktu.
	* @param plane Dane plaszczyzny.
	* @return Odleglosc punktu od plaszczyzny.
	*/
	float DistPointPlane(const btVector3& p, const btPlane& plane);

	/** Zaokragla podana wartosc do dwoch miejsc po przecinku
	* @param x Wartosc do zaokraglenia.
	* @return Zaokraglona wartosc.
	*/
	inline float Round(float x)
	{
		int tmp = x * 100;

		return floorf(x * 100 + 0.5) / 100.0f;
		

		return x;
	}
};

